package com.bubbles.workspace.sync.entity.source.metadata;


import com.bubbles.engine.data.core.entity.BaseEntity;
import com.bubbles.workspace.sync.entity.source.constraint.*;
import com.bubbles.workspace.sync.entity.source.enhance.SourceEnhanceDimension;
import com.bubbles.workspace.sync.entity.source.enhance.SourceEnhanceDorisAnalyzeTable;
import com.bubbles.workspace.sync.entity.source.enhance.SourceEnhanceIncrement;
import com.bubbles.workspace.sync.enums.SourceEnabledReason;
import com.bubbles.workspace.sync.key.source.metadata.SourceTableKey;
import jakarta.persistence.*;
import lombok.*;
import lombok.experimental.Accessors;
import org.hibernate.annotations.Comment;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>description: 源数据源-表 </p>
 *
 * @author CryptoNeedle
 * @date 2025-06-19
 */
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true, exclude = {"sourceDatabase", "sourceColumns", "sourceConstraintPrimaries", "sourceConstraintUniques", "sourceConstraintForeigns", "sourceConstraintChecks", "sourceIndexUniques", "sourceEnhanceIncrements", "sourceEnhanceDimensions"})
@ToString(callSuper = true, exclude = {"sourceDatabase", "sourceColumns", "sourceConstraintPrimaries", "sourceConstraintUniques", "sourceConstraintForeigns", "sourceConstraintChecks", "sourceIndexUniques", "sourceEnhanceIncrements", "sourceEnhanceDimensions"})
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(schema = "sync", name = "source_table")
@IdClass(SourceTableKey.class)
@Comment("源数据源-表")
public class SourceTable extends BaseEntity {
    
    @Id
    @Comment("源数据源-目录名称")
    private String sourceCatalogName;
    
    @Comment("源数据源-系统编码")
    private String sourceSystemCode;
    
    @Id
    @Comment("源数据源-数据库名称")
    private String sourceDatabaseName;
    
    @Id
    @Comment("源数据源-表名称")
    private String sourceTableName;
    
    @Column(columnDefinition = "TEXT")
    @Comment("源数据源-表评论")
    private String sourceTableComment;
    
    @Comment("源数据源-人工指定表评论")
    private Boolean sourceTableCommentManual;
    
    @Comment("源数据源-启用表")
    private Boolean sourceTableEnabled;
    
    @Enumerated(EnumType.STRING)
    @Comment("源数据源-启用或关闭表原因")
    private SourceEnabledReason sourceTableEnabledReason;
    
    // todo
    @Comment("源数据源-维度名称")
    private String sourceDimensionName;
    
    @Embedded
    private SourceStatistic sourceStatistic;
    
    @Embedded
    private DorisStatistic dorisStatistic;
    
    @Embedded
    private DetailStatistic detailStatistic;
    
    @Embedded
    private Transform transform;
    
    @Embedded
    private Doris doris;
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class SourceStatistic {
        
        @Comment("源数据源统计信息-数据量")
        private Long sourceStatisticRowCount;
        
        @Comment("源数据源统计信息-统计时间")
        private Date sourceStatisticDatetime;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class DorisStatistic {
        
        @Comment("Doris统计信息-数据量")
        private Long dorisStatisticRowCount;
        
        @Comment("Doris统计信息-统计时间")
        private Date dorisStatisticDatetime;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class DetailStatistic {
        
        @Comment("详细统计信息-数据量")
        private Long detailStatisticRowCount;
        
        @Comment("详细统计信息-统计时间")
        private Date detailStatisticDatetime;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class Transform {
        
        @Comment("转换-系统编码")
        private String transformSystemCode;
        
        @Comment("转换-表名称")
        private String transformTableName;
        
        @Column(columnDefinition = "TEXT")
        @Comment("转换-表评论")
        private String transformTableComment;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class Doris {
        
        @Comment("DORIS-数据库名称")
        private String dorisDatabaseName;
        
        @Comment("DORIS-表名称")
        private String dorisTableName;
        
        @Comment("DORIS-需要同步")
        private Boolean dorisNeededSync;
    }
    
    /**
     * 关联关系
     */
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({@JoinColumn(name = "sourceCatalogName", referencedColumnName = "sourceCatalogName", insertable = false, updatable = false), @JoinColumn(name = "sourceDatabaseName", referencedColumnName = "sourceDatabaseName", insertable = false, updatable = false)})
    private SourceDatabase sourceDatabase;
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceColumn> sourceColumns = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceConstraintPrimary> sourceConstraintPrimaries = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceConstraintUnique> sourceConstraintUniques = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceConstraintForeign> sourceConstraintForeigns = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceConstraintCheck> sourceConstraintChecks = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceIndexUnique> sourceIndexUniques = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceEnhanceIncrement> sourceEnhanceIncrements = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceEnhanceDimension> sourceEnhanceDimensions = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceTable", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceEnhanceDorisAnalyzeTable> sourceEnhanceDorisAnalyzeTables = new ArrayList<>();
    
    public SourceTable addSourceColumn(SourceColumn sourceColumn) {
        this.sourceColumns.add(sourceColumn);
        sourceColumn.setSourceTable(this);
        sourceColumn.setSourceCatalogName(this.sourceCatalogName);
        sourceColumn.setSourceDatabaseName(this.sourceDatabaseName);
        sourceColumn.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceColumn(SourceColumn sourceColumn) {
        this.sourceColumns.remove(sourceColumn);
        sourceColumn.setSourceTable(null);
        return this;
    }
    
    public SourceTable addSourceConstraintPrimary(SourceConstraintPrimary sourceConstraintPrimary) {
        this.sourceConstraintPrimaries.add(sourceConstraintPrimary);
        sourceConstraintPrimary.setSourceTable(this);
        sourceConstraintPrimary.setSourceCatalogName(this.sourceCatalogName);
        sourceConstraintPrimary.setSourceDatabaseName(this.sourceDatabaseName);
        sourceConstraintPrimary.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceConstraintPrimary(SourceConstraintPrimary sourceConstraintPrimary) {
        this.sourceConstraintPrimaries.remove(sourceConstraintPrimary);
        sourceConstraintPrimary.setSourceTable(null);
        return this;
    }
    
    public SourceTable addSourceConstraintUnique(SourceConstraintUnique sourceConstraintUnique) {
        this.sourceConstraintUniques.add(sourceConstraintUnique);
        sourceConstraintUnique.setSourceTable(this);
        sourceConstraintUnique.setSourceCatalogName(this.sourceCatalogName);
        sourceConstraintUnique.setSourceDatabaseName(this.sourceDatabaseName);
        sourceConstraintUnique.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceConstraintUnique(SourceConstraintUnique sourceConstraintUnique) {
        this.sourceConstraintUniques.remove(sourceConstraintUnique);
        sourceConstraintUnique.setSourceTable(null);
        return this;
    }
    
    public SourceTable addSourceConstraintForeign(SourceConstraintForeign sourceConstraintForeign) {
        this.sourceConstraintForeigns.add(sourceConstraintForeign);
        sourceConstraintForeign.setSourceTable(this);
        sourceConstraintForeign.setSourceCatalogName(this.sourceCatalogName);
        sourceConstraintForeign.setSourceDatabaseName(this.sourceDatabaseName);
        sourceConstraintForeign.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceConstraintForeign(SourceConstraintForeign sourceConstraintForeign) {
        this.sourceConstraintForeigns.remove(sourceConstraintForeign);
        sourceConstraintForeign.setSourceTable(null);
        return this;
    }
    
    public SourceTable addSourceConstraintCheck(SourceConstraintCheck sourceConstraintCheck) {
        this.sourceConstraintChecks.add(sourceConstraintCheck);
        sourceConstraintCheck.setSourceTable(this);
        sourceConstraintCheck.setSourceCatalogName(this.sourceCatalogName);
        sourceConstraintCheck.setSourceDatabaseName(this.sourceDatabaseName);
        sourceConstraintCheck.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceConstraintCheck(SourceConstraintCheck sourceConstraintCheck) {
        this.sourceConstraintChecks.remove(sourceConstraintCheck);
        sourceConstraintCheck.setSourceTable(null);
        return this;
    }
    
    public SourceTable addSourceIndexUnique(SourceIndexUnique sourceIndexUnique) {
        this.sourceIndexUniques.add(sourceIndexUnique);
        sourceIndexUnique.setSourceTable(this);
        sourceIndexUnique.setSourceCatalogName(this.sourceCatalogName);
        sourceIndexUnique.setSourceDatabaseName(this.sourceDatabaseName);
        sourceIndexUnique.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceIndexUnique(SourceIndexUnique sourceIndexUnique) {
        this.sourceIndexUniques.remove(sourceIndexUnique);
        sourceIndexUnique.setSourceTable(null);
        return this;
    }
    
    public SourceTable addSourceEnhanceTableIncrement(SourceEnhanceIncrement sourceEnhanceIncrement) {
        this.sourceEnhanceIncrements.add(sourceEnhanceIncrement);
        sourceEnhanceIncrement.setSourceTable(this);
        sourceEnhanceIncrement.setSourceCatalogName(this.sourceCatalogName);
        sourceEnhanceIncrement.setSourceDatabaseName(this.sourceDatabaseName);
        sourceEnhanceIncrement.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceEnhanceTableIncrement(SourceEnhanceIncrement sourceEnhanceIncrement) {
        this.sourceEnhanceIncrements.remove(sourceEnhanceIncrement);
        sourceEnhanceIncrement.setSourceTable(null);
        return this;
    }
    
    public SourceTable addSourceEnhanceTableDimension(SourceEnhanceDimension sourceEnhanceDimension) {
        this.sourceEnhanceDimensions.add(sourceEnhanceDimension);
        sourceEnhanceDimension.setSourceTable(this);
        sourceEnhanceDimension.setSourceCatalogName(this.sourceCatalogName);
        sourceEnhanceDimension.setSourceDatabaseName(this.sourceDatabaseName);
        sourceEnhanceDimension.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceEnhanceTableDimension(SourceEnhanceDimension sourceEnhanceDimension) {
        this.sourceEnhanceDimensions.remove(sourceEnhanceDimension);
        sourceEnhanceDimension.setSourceTable(null);
        return this;
    }
    
    public SourceTable addSourceEnhanceDorisAnalyzeTable(SourceEnhanceDorisAnalyzeTable sourceEnhanceDorisAnalyzeTable) {
        this.sourceEnhanceDorisAnalyzeTables.add(sourceEnhanceDorisAnalyzeTable);
        sourceEnhanceDorisAnalyzeTable.setSourceTable(this);
        sourceEnhanceDorisAnalyzeTable.setSourceSystemCode(this.sourceSystemCode);
        sourceEnhanceDorisAnalyzeTable.setSourceDatabaseName(this.sourceDatabaseName);
        sourceEnhanceDorisAnalyzeTable.setSourceTableName(this.sourceTableName);
        return this;
    }
    
    public SourceTable removeSourceEnhanceDorisAnalyzeTable(SourceEnhanceDorisAnalyzeTable sourceEnhanceDorisAnalyzeTable) {
        this.sourceEnhanceDorisAnalyzeTables.remove(sourceEnhanceDorisAnalyzeTable);
        sourceEnhanceDorisAnalyzeTable.setSourceTable(null);
        return this;
    }
    
    /**
     * 其他
     */
    public SourceTableKey getKey() {
        return new SourceTableKey().setSourceCatalogName(this.sourceCatalogName)
                                   .setSourceDatabaseName(this.sourceDatabaseName)
                                   .setSourceTableName(this.sourceTableName);
    }
    
    public String getStringKey() {
        return getKey().toString();
    }
}